package com.ltu.util.datetime;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

import org.apache.commons.lang3.StringUtils;
import org.springframework.transaction.annotation.Transactional;

/**
 * 日期工具类
 * 
 * @author Jarlun
 */
public class DateUtils {

	public static final String TIME_INTERVAL_SECOND = "second";
	public static final String TIME_INTERVAL_MINUTE = "minute";
	public static final String TIME_INTERVAL_HOUR = "hour";
	public static final String TIME_INTERVAL_DAY = "day";
	public static final String TIME_INTERVAL_WEEK = "week";
	public static final String TIME_INTERVAL_MONTH = "month";
	public static final String TIME_INTERVAL_QUARTER = "quarter";
	public static final String TIME_INTERVAL_YEAR = "year";
	public static final String DATE_FORMAT = "yyyy-MM-dd";
	public static final String TIME_FORMAT = "HH:mm:ss";
	public static final String HOUR_FORMAT = "HH:mm";
	public static final String DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
	public static final String DATE_HH_FORMAT = "yyyy-MM-dd HH";
	public static final String DATE_HH_MM_FORMAT = "yyyy-MM-dd HH:mm";
	public static final String TIMESTAMP_FORMAT = "yyyy-MM-dd HH:mm:ss.S";
	public static final String DATE_FORMAT_NUMBER = "yyyyMMdd";
	public static final String DATE_TIME_FORMAT_NUMBER = "yyyyMMddHHmmssSSS";
	public static final String DATE_TIME_YMDHMS="yyMMddHHmmss";

	public static Date parse(String dateString, String dateFormat) {
		return parse(dateString, dateFormat, Date.class);
	}

	public static <T extends Date> T parse(String dateString, String dateFormat, Class<T> targetResultType) {
		if (StringUtils.isEmpty(dateString))
			return null;
		
		DateFormat df = new SimpleDateFormat(dateFormat);
		try {
			T t = targetResultType.getConstructor(new Class[] { Long.TYPE })
					.newInstance(
							new Object[] { Long.valueOf(df.parse(dateString)
									.getTime()) });
			return t;
		} catch (ParseException e) {
			String errorInfo = "cannot use dateformat:" + dateFormat
					+ " parse datestring:" + dateString;
			throw new IllegalArgumentException(errorInfo, e);
		} catch (Exception e) {
			throw new IllegalArgumentException("error targetResultType:"
					+ targetResultType.getName(), e);
		}
	}
	
	/**
	 * 根据出生日期计算年龄
	 * @param birthDay
	 * @return
	 */
	public static int getAge(Date birthDay) {
		Calendar cal = Calendar.getInstance();
		if (cal.before(birthDay)) { // 出生日期晚于当前时间，无法计算
			throw new IllegalArgumentException("The birthDay is before Now.It's unbelievable!");
		}
		int yearNow = cal.get(Calendar.YEAR); // 当前年份
		int monthNow = cal.get(Calendar.MONTH); // 当前月份
		int dayOfMonthNow = cal.get(Calendar.DAY_OF_MONTH); // 当前日期
		cal.setTime(birthDay);
		int yearBirth = cal.get(Calendar.YEAR);
		int monthBirth = cal.get(Calendar.MONTH);
		int dayOfMonthBirth = cal.get(Calendar.DAY_OF_MONTH);
		int age = yearNow - yearBirth; // 计算整岁数
		if (monthNow <= monthBirth) {
			if (monthNow == monthBirth) {
				if (dayOfMonthNow < dayOfMonthBirth)
					age--;// 当前日期在生日之前，年龄减一
			} else {
				age--;// 当前月份在生日之前，年龄减一

			}
		}
		return age;
	}

	public static String dateToStr(Date date,String pattern) {
	       if (date == null || date.equals(""))
	    	 return null;
	       SimpleDateFormat formatter = new SimpleDateFormat(pattern);
	       return formatter.format(date);
	} 
	
	public static String format(Date date, String dateFormat) {
		if (date == null)
			return null;
		return new SimpleDateFormat(dateFormat).format(date);
	}

	public static String format(String datePattern) {
		return new SimpleDateFormat(datePattern).format(currentTime());
	}

	public static Date add(int field, Date date, int value) {
		if (value == 0) {
			return date;
		}
		Calendar c = Calendar.getInstance();
		c.setTime(date);

		int fieldNewValue = (c.get(field) + value);
		c.set(field, fieldNewValue);
		return c.getTime();
	}

	public static long dateDiff(String timeInterval, Date date1, Date date2) {
		Calendar calendar = Calendar.getInstance();
		if (timeInterval.equals(TIME_INTERVAL_YEAR)) {
			calendar.setTime(date1);
			int time = calendar.get(Calendar.YEAR);
			calendar.setTime(date2);
			return time - calendar.get(Calendar.YEAR);
		}

		if (timeInterval.equals(TIME_INTERVAL_QUARTER)) {
			calendar.setTime(date1);
			int time = calendar.get(Calendar.YEAR) * 4;
			calendar.setTime(date2);
			time -= calendar.get(Calendar.YEAR) * 4;
			calendar.setTime(date1);
			time += calendar.get(Calendar.MONTH) / 4;
			calendar.setTime(date2);
			return time - calendar.get(Calendar.MONTH) / 4;
		}

		if (timeInterval.equals(TIME_INTERVAL_MONTH)) {
			calendar.setTime(date1);
			int time = calendar.get(Calendar.YEAR) * 12;
			calendar.setTime(date2);
			time -= calendar.get(Calendar.YEAR) * 12;
			calendar.setTime(date1);
			time += calendar.get(Calendar.MONTH);
			calendar.setTime(date2);
			return time - calendar.get(Calendar.MONTH);
		}

		if (timeInterval.equals(TIME_INTERVAL_WEEK)) {
			calendar.setTime(date1);
			int time = calendar.get(Calendar.YEAR) * 52;
			calendar.setTime(date2);
			time -= calendar.get(Calendar.YEAR) * 52;
			calendar.setTime(date1);
			time += calendar.get(Calendar.WEEK_OF_YEAR);
			calendar.setTime(date2);
			return time - calendar.get(Calendar.WEEK_OF_YEAR);
		}

		if (timeInterval.equals(TIME_INTERVAL_DAY)) {
			calendar.setTime(date1);
			int time = calendar.get(Calendar.DAY_OF_YEAR)
					+ calendar.get(Calendar.YEAR) * 365;
			calendar.setTime(date2);
			return time
					- (calendar.get(Calendar.DAY_OF_YEAR) + calendar
							.get(Calendar.YEAR) * 365);
		}

		if (timeInterval.equals(TIME_INTERVAL_HOUR)) {
			long time = date1.getTime() / 1000 / 60 / 60;
			return time - date2.getTime() / 1000 / 60 / 60;
		}

		if (timeInterval.equals(TIME_INTERVAL_MINUTE)) {
			long time = date1.getTime() / 1000 / 60;
			return time - date2.getTime() / 1000 / 60;
		}

		if (timeInterval.equals(TIME_INTERVAL_SECOND)) {
			long time = date1.getTime() / 1000;
			return time - date2.getTime() / 1000;
		}

		return date1.getTime() - date2.getTime();
	}

	public static BigDecimal hourDiffDouble(Date date1, Date date2) {
		int diff = calLastedTime(date2, date1);
		
		int h = (int) diff/ 60;
		int m = (int) diff % 60;
		BigDecimal d = new BigDecimal(m).divide(new BigDecimal(60),1,RoundingMode.CEILING);
		return new BigDecimal(h).add(d);
	}
	
	public static long hourDiff(String timeInterval, Long unixTime1,
			Long unixTime2) {
		return dateDiff(timeInterval, new Date(unixTime1), new Date(unixTime2));
	}
	
	/**
	 * 格式化某个日期为凌晨时间
	 * @param date
	 * @return
	 */
	public static Date toZeroDate(Date date) {
		if (date == null) {
			return null;
		}
		Calendar c = Calendar.getInstance();
		c.setTime(date);
		c.set(Calendar.HOUR_OF_DAY, 0);
		c.set(Calendar.MINUTE, 0);
		c.set(Calendar.SECOND, 0);
		return c.getTime();
	}
	
	/**
	 * 格式化某个日期为当月的一号
	 * @param date
	 * @return
	 */
	public static Date toZeroMonth(Date date) {
		if (date == null) {
			return null;
		}
		Calendar c = Calendar.getInstance();
		c.setTime(date);
		c.set(Calendar.DATE, 1);
		c.set(Calendar.HOUR_OF_DAY, 0);
		c.set(Calendar.MINUTE, 0);
		c.set(Calendar.SECOND, 0);
		return c.getTime();
	}
	
	/**
	 * 获取当天的凌晨时间
	 * @return
	 */
	public static Date toZeroDate(){
		return toZeroDate(currentTime());
	}
	
	/**
	 * 获取 GMT 格式时间格式的字符串
	 */
	public static String getGMTTime() {
		SimpleDateFormat formater = new SimpleDateFormat(
				"EEE, d MMM yyyy HH:mm:ss 'GMT'", Locale.US);
		formater.setTimeZone(TimeZone.getTimeZone("GMT"));
		return formater.format(currentTime());
	}

	/**
	 * @desc 根据类型，获取当前时间 下一个时间
	 * @param timeType 1 分 2 时  3 月 4年
	 * @param dis
	 * @return date
	 */
	public static Date getTimeByType(Date date,Integer timeType,Integer dis){

		Calendar now = Calendar.getInstance();
		now.setTime(date);
		switch (timeType)
		{
			case 1:
				now.add(Calendar.MINUTE,dis);
				return now.getTime();
			case 2:
				now.add(Calendar.HOUR,dis);
				return now.getTime();
			case 3:
				now.add(Calendar.MONTH,dis);
				return now.getTime();
			case 4:
				now.add(Calendar.YEAR,dis);
				return now.getTime();

		}

		return now.getTime();


	}

	/**
	 * @desc 根据时间类型获取当前的时间类型
	 * @param date 当前时间
	 * @param timeType 查找时间类型 1 当天 2 本周 3 按月 4 按季度 5 按年
	 **/
	public static String getTimeTypeByNowDate(Date date,Integer timeType){
		switch (timeType){
			case 1:
				return format(date,DATE_FORMAT);
			case 2:
				return getWeek(date).toString();
			case 3:
				return getMonth(date).toString();
			case 4:
				return getQuarter(date);
			case 5:
				return getYear(date);
			default:
				return null;
		}
	}

	/**
	 * 获取当前时间字符串 yyyyMMdd
	 * @return
	 */
	public static String currentDayString() {
		return format(new Date(),DATE_FORMAT_NUMBER);
	}


	/**
	 * 获取当前时间
	 * 
	 * @return
	 */
	public static Date currentTime() {
		return new Date();
	}

	/**
	 * 当前毫秒数
	 * 
	 * @return
	 */
	public static Long currentMillis() {
		return System.currentTimeMillis();
	}

	/**
	 * 当前秒数
	 * 
	 * @return
	 */
	public static Long currentSecs() {
		return currentMillis() / 1000;
	}

    /**
     * 判断时间是不是今天
     * @param date
     * @return    是返回true，不是返回false
     */
    public static boolean isToday(Date date) {
        //当前时间
        Date now = new Date();
        SimpleDateFormat sf = new SimpleDateFormat("yyyyMMdd");
        //获取今天的日期
        String nowDay = sf.format(now);
         
         
        //对比的时间
        String day = sf.format(date);
         
        return day.equals(nowDay);
    }
    

    /**
     * 获得两日期相差多少年多少天
     * @param date
     * @return    是返回true，不是返回false
     */
    public static String diffYearAndMonth(Date date) {
    	Date now1 = new Date();
    	long l=now1.getTime()-date.getTime();
    	long day=l/(24*60*60*1000);
    	long mon=day/30;
    	long year=mon/12;
    	long diffMon = mon%12;
    	String yearAndMonth = "至今";
    	if (year >0) {
    		yearAndMonth = yearAndMonth + year + "年";
		}
    	if (diffMon > 9) {
    		yearAndMonth = yearAndMonth + diffMon + "个月";
		}else if (diffMon > 0 && diffMon < 9) {
			yearAndMonth = yearAndMonth + "零" + diffMon + "个月";
		}
	    return yearAndMonth;
    }
    
    /*
     * 当周的第几天
     * return Integer
     */
	public static Integer howWeek() {
		boolean isFirstSunday = (Calendar.getInstance().getFirstDayOfWeek() == Calendar.SUNDAY);
		String str[] = { "星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六" };// 字符串数组
		Calendar rightNow = Calendar.getInstance();
		int day = rightNow.get(rightNow.DAY_OF_WEEK);// 获取时间
		if (isFirstSunday) {
			day = day - 1;
			if (day == 0) {
				day = 7;
			}
		}
		return day;
	} 
    
	/** 
	 * 获取本周是当年的第几周
	 * 
	 */  
	public static Integer getWeek() {
		Calendar now = Calendar.getInstance();
		now.setFirstDayOfWeek(Calendar.MONDAY);
		int week = now.get(now.WEEK_OF_YEAR);
		return week;
	}

	/**
	 * 获取第几周
	 * @param date
	 * @return
	 */
	public static Integer getWeek(Date date) {
		Calendar time = Calendar.getInstance();
		time.setTime(date);
		time.setFirstDayOfWeek(Calendar.MONDAY);
		int week = time.get(time.WEEK_OF_YEAR);
		return week;
	}
	
	/** 
	 * 获取当前月 
	 * 
	 */  
	public static Integer getMonth() {
		Calendar now = Calendar.getInstance();
		int month = now.get(now.MONTH)+1;
		return month;
		
	}
	
	/** 
	 * 获取月份 
	 */  
	@SuppressWarnings("static-access")
	public static Integer getMonth(Date date) {
		Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
		int month = calendar.get(calendar.MONTH)+1;
		return month;
	}

	/**
	 * 获取当前时间 是不是每月第一天
	 *
	 */
	public static Integer getMonthDay(){
		Date now = new Date();
		SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd");//可以方便地修改日期格式


		String curr = dateFormat.format( now );
		System.out.println("当前日期:" + curr);

		Calendar c = Calendar.getInstance();//可以对每个时间域单独修改

		int year = c.get(Calendar.YEAR);
		int month = c.get(Calendar.MONTH);
		int date = c.get(Calendar.DATE);

		return date;
	}


	/** 
	 * 获取当前季度 
	 * 
	 */  
	public static String getQuarter() {  
	    Calendar c = Calendar.getInstance();  
	    int month = c.get(c.MONTH) + 1;  
	    int quarter = 0;  
	    if (month >= 1 && month <= 3) {  
	        quarter = 1;  
	    } else if (month >= 4 && month <= 6) {  
	        quarter = 2;  
	    } else if (month >= 7 && month <= 9) {  
	        quarter = 3;  
	    } else {  
	        quarter = 4;  
	    }  
	    return quarter + "";  
	}

	/**
	 * 获取季度
	 *
	 */
	public static String getQuarter(Date date) {
		Calendar time = Calendar.getInstance();
		time.setTime(date);
		int month = time.get(time.MONTH) + 1;
		int quarter = 0;
		if (month >= 1 && month <= 3) {
			quarter = 1;
		} else if (month >= 4 && month <= 6) {
			quarter = 2;
		} else if (month >= 7 && month <= 9) {
			quarter = 3;
		} else {
			quarter = 4;
		}
		return quarter + "";
	}
	  
	
	/** 
	 * 获取当前年份
	 * 
	 */  
	public static String getYear() {
		Calendar now = Calendar.getInstance();
		int year = now.get(now.YEAR);
		
		return year+"";
		
	}

	/**
	 * 获取当前年份
	 *
	 */
	public static String getYear(Date date) {
		Calendar time = Calendar.getInstance();
		time.setTime(date);
		int year = time.get(time.YEAR);
		return year+"";
	}
	
	public static long getDistanceDays(String str1, String str2) throws Exception{  
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  
        Date one;  
        Date two;  
        long days=0;  
        try {  
            one = df.parse(str1);  
            two = df.parse(str2);  
            long time1 = one.getTime();  
            long time2 = two.getTime();  
            long diff ;  
            if(time1<time2) {  
                diff = time2 - time1;  
            } else {  
                diff = time1 - time2;  
            }  
            days = diff / (1000 * 60 * 60 * 24);  
        } catch (ParseException e) {  
            e.printStackTrace();  
        }  
        return days;  
    }  
	
    /*
     * 分钟差
     * return Integer
     */
	public  static int calLastedTime(Date firstDate, Date secondDate) {
		  long a = firstDate.getTime();
		  long b = secondDate.getTime();
		  int c = (int)((b - a) / 1000)/60;
		  return c;
	}
	
    /*
     * 判断是否为本月第一天
     * return boolean
     */
	public  static boolean isFirstDayForMontu() {
		boolean isFirst = false;
		// 获得一个日历对象
		Calendar c = Calendar.getInstance();
		// 得到本月的那一天
		int today = c.get(c.DAY_OF_MONTH);
		// 然后判断是不是本月的第一天
		if(today == 1){
		//是
			isFirst = true;
		}
		return isFirst;
	}

	 /** 
	  * 时间戳转换成日期格式字符串 
	  * @param seconds 精确到秒的字符串 
	  * @param formatStr 
	  * @return 
	 */  
	 public static String timeStamp2Date(String seconds,String format) {  
	    if(seconds == null || seconds.isEmpty() || seconds.equals("null")){  
	          return "";  
        }  
        if(format == null || format.isEmpty()){
        	 format = "yyyy-MM-dd HH:mm:ss";
      }   
      SimpleDateFormat sdf = new SimpleDateFormat(format);  
      return sdf.format(new Date(Long.valueOf(seconds+"000")));  
     }  
    /** 
      * 日期格式字符串转换成时间戳 
      * @param date 字符串日期 
      * @param format 如：yyyy-MM-dd HH:mm:ss 
      * @return 
      **/  
	  public static String date2TimeStamp(String date_str,String format){  
	     try {  
	          SimpleDateFormat sdf = new SimpleDateFormat(format);  
	          return String.valueOf(sdf.parse(date_str).getTime()/1000);  
	     } catch (Exception e) {  
	          e.printStackTrace();  
         }  
	        return "";  
	    }  
	      
	 /** 
	  * 取得当前时间戳（精确到秒） 
	  * @return 
	 */  
      public static String timeStamp(){  
        long time = System.currentTimeMillis();
	         String t = String.valueOf(time/1000);  
	    return t;  
	   }
	/**
	 * @Description:按小时分割时间段
	 * @return 分割的时间段数组
	 * @param startTime 开始时间
	 * @param endTime 结束时间
	 */
	@Transactional
	public static List<String> getTimeDisplit(String startTime, String endTime, String day) {
		List<String> time = new ArrayList<>();

		String s = DateUtils.date2TimeStamp(startTime, DateUtils.TIME_FORMAT);
		String e = DateUtils.date2TimeStamp(endTime, DateUtils.TIME_FORMAT);

		if(Integer.valueOf(e)<=Integer.valueOf(s)){
			try {

				SimpleDateFormat sdf = new SimpleDateFormat("HH:mm");
				Date st =str2Date(day+" "+startTime,"yyyy-MM-dd HH:mm:ss");
				Date en =str2Date(day+" "+endTime,"yyyy-MM-dd HH:mm:ss");

				Calendar ca = Calendar.getInstance();
				ca.setTime(st);

				Calendar cal = Calendar.getInstance();
				cal.setTime(en);
				cal.add(Calendar.DAY_OF_YEAR, 1);

				Long sd = cal.getTimeInMillis()-ca.getTimeInMillis();
				System.out.println("111111111***"+ca.getTimeInMillis()+"gettime"+ca.getTime());
				System.out.println("222222222***"+cal.getTimeInMillis()+"gettime"+cal.getTime());
				long hours = (sd % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60);

				Calendar c = Calendar.getInstance();
				c.setTime(sdf.parse(startTime));
				for (int i = 0; i <= Math.abs(hours); i++) {
					time.add(sdf.format(c.getTime()));
					c.add(Calendar.MINUTE, 60);
				}

			} catch (ParseException e1) {

				e1.printStackTrace();
			}

		}else{
			for (int i = Integer.valueOf(s); i <=Integer.valueOf(e) ;) {
				String splitTime = DateUtils.timeStamp2Date(String.valueOf(i),DateUtils.TIME_FORMAT);
				time.add(splitTime.substring(0, 5));
				i+=3600;
			}
		}


		return time;
	}

	public static Date str2Date(String date,String format){
		DateFormat dateFormat = new SimpleDateFormat(format);
		Date result = null;
		try {
			result = dateFormat.parse(date);
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return result;
	}

//	    public static void main(String[] args) {  
//	         String timeStamp = timeStamp();  
//        System.out.println("timeStamp="+timeStamp); //运行输出:timeStamp=1470278082
//        System.out.println(System.currentTimeMillis());//运行输出:1470278082980
//         //该方法的作用是返回当前的计算机时间，时间的表达格式为当前计算机时间和GMT时间(格林威治时间)1970年1月1号0时0分0秒所差的毫秒数
//	        
//        String date = timeStamp2Date(timeStamp, "yyyy-MM-dd HH:mm:ss");  
//	        System.out.println("date="+date);//运行输出:date=2016-08-04 10:34:42
//        
//	         String timeStamp2 = date2TimeStamp(date, "yyyy-MM-dd HH:mm:ss");  
//	       System.out.println(timeStamp2);  //运行输出:1470278082
//    }
	
    public static void main(String[] args) {
    	//System.out.println(diffYearAndMonth(parse("2016-10-12 12:54:63", DATE_TIME_FORMAT)));
    	//howWeek();
    	//System.out.println(calLastedTime(new Date(), parse("2017-11-17 02:39:00", DATE_TIME_FORMAT)));
    	//System.out.println(dateDiff("month", new Date(), parse("2009-12-01 08:23:28", DATE_TIME_FORMAT))/12);
    	//hourDiffDouble(new Date(), parse("2017-11-20 11:30:00", DATE_TIME_FORMAT));
		Date date = getTimeByType(new Date(),2,-24);
    	System.out.println(format(date,DATE_TIME_FORMAT));
	}
}